using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace RapidHDL
{
    public enum SelectedHardwareType
    {
        Root,
        Sources,
        Source,
        Views,
        View,
        TopHardware,
        Component,
        NVSource,
        NVSink,
        NVPassthrough,
        Verilog,
        Log,
        Unknown
    }

    public class HardwareTreeVeiw
    {
        public TreeNode Root;
        
        public TreeNode SignalSources;
        public TreeNode SignalViews;
        public TreeNode Hardware;
        public TreeNode Logs;

        System.Windows.Forms.TreeView tvTree;
        int iStartImageIndex;
        RapidHardware oRapidHardware;

        int iImgSources;
        int iImgSource;
        int iImgViews;
        int iImgView;
        int iImgHardware;
        int iImgComponent;
        int iImgNVSource;
        int iImgNVSink;
        int iImgNVPassthrough;
        int iImgNVSources;
        int iImgComponentSignals;
        int iImgComponentChildren;
        int iImgVerilog;
        int iImgLog;

        public HardwareTreeVeiw(RapidHardware poRapidHardware, System.Windows.Forms.TreeView ptvTree, System.Windows.Forms.TreeNode ptvRoot, int piStartImageIndex)
        {
            tvTree = ptvTree;
            iStartImageIndex = piStartImageIndex;
            oRapidHardware = poRapidHardware;
            
            //oTreeRoot;

            Root = ptvRoot;
            iImgSources = piStartImageIndex;
            iImgSource = piStartImageIndex + 1;
            iImgViews = piStartImageIndex;
            iImgView = piStartImageIndex + 2;
            iImgHardware = piStartImageIndex + 3;
            iImgComponent = piStartImageIndex + 4;
            iImgNVSource = piStartImageIndex + 5;
            iImgNVSink = piStartImageIndex + 6;
            iImgNVPassthrough = piStartImageIndex + 7;
            iImgComponentChildren = piStartImageIndex + 8;
            iImgComponentSignals = piStartImageIndex + 9;
            iImgVerilog = piStartImageIndex + 10;
            iImgLog = piStartImageIndex + 11;


            SignalSources = new TreeNode("Signal Sources", iImgSources, iImgSources);
            SignalViews = new TreeNode("Signal Views", iImgViews, iImgViews);
            Hardware = new TreeNode("Hardware", iImgHardware, iImgHardware);
            Logs = new TreeNode("Xilinx Logs", iImgLog, iImgLog);

            Root.Nodes.Add(SignalSources);
            Root.Nodes.Add(SignalViews);
            Root.Nodes.Add(Logs);

            Hardware.Tag = oRapidHardware;

            oRapidHardware.DisplayManager.RegisterTreeView(this);
        }

        public void ReloadTree()
        {
            TreeNode oNode;
            Root.TreeView.BeginUpdate();
            SignalSources.Nodes.Clear();
            foreach (SignalSource oSignalSource in oRapidHardware.SystemInterface.SignalSources.Values)
            {
                string sName = SourceNodeText(oSignalSource);
                if (!oSignalSource.Hidden)
                {
                    oNode = new TreeNode(sName, iImgSource, iImgSource);
                    oNode.Tag = oSignalSource;
                    SignalSources.Nodes.Add(oNode);
                }
            }

            SignalViews.Nodes.Clear();
            foreach (SignalView oSignalView in oRapidHardware.SystemInterface.SignalViews.Values)
            {
                string sName = ViewNodeText(oSignalView);
                if (!oSignalView.Hidden)
                {
                    oNode = new TreeNode(sName, iImgView, iImgView);
                    oNode.Tag = oSignalView;
                    SignalViews.Nodes.Add(oNode);
                }
            }

            RecurseComponentTree(oRapidHardware.Structure.TopLevelComponent, Root);

            string[] saLogs = XilinxTools.LogFileNames(oRapidHardware.Settings.TopComponentName);
            foreach (string sLogFile in saLogs)
            {
                string sFileName = TextFile.BuildFileName(oRapidHardware.Settings.OutputPath, sLogFile);
                oNode = new TreeNode(sLogFile, iImgLog, iImgLog);
                oNode.Tag = sFileName;
                Logs.Nodes.Add(oNode);
            }
            Root.TreeView.Sort();
            Root.TreeView.EndUpdate();
        }

        public void RefreshTree()
        {
            Root.TreeView.BeginUpdate();
            foreach (TreeNode oNode in SignalSources.Nodes)
            {
                SignalSource oSignalSource = (SignalSource)oNode.Tag;
                oNode.Text = SourceNodeText(oSignalSource);
            }
            foreach (TreeNode oNode in SignalViews.Nodes)
            {
                SignalView oSignalView = (SignalView)oNode.Tag;
                string sText =  ViewNodeText(oSignalView);
                oNode.Text = sText;
            }
            Root.TreeView.EndUpdate();
        }

        private string SourceNodeText(SignalSource poSignalSource)
        {
            //return poSignalSource.FormattedValue + "    |     " + poSignalSource.Name;
            return poSignalSource.Name + "    |     " + poSignalSource.FormattedValue;
        }

        private string ViewNodeText(SignalView poSignalView)
        {
            //return poSignalView.FormattedValue + "    |     " + poSignalView.Name;
            return poSignalView.Name + "    |     " + poSignalView.FormattedValue;
        }

        public object GetSelectedObject(TreeNode ptnNode)
        {
            if (ptnNode.ImageIndex == iImgSource)
                return (SignalSource)ptnNode.Tag;
            if (ptnNode.ImageIndex == iImgView)
                    return (SignalView) ptnNode.Tag;
            return null;
        }

        public SelectedHardwareType GetSelectedHardwareType(TreeNode ptnNode)
        {
            if (iImgComponent == ptnNode.ImageIndex)
                return SelectedHardwareType.Component;
            if (ptnNode.ImageIndex == iImgHardware)
                return SelectedHardwareType.TopHardware;
            if (ptnNode.ImageIndex == iImgNVPassthrough)
                return SelectedHardwareType.NVPassthrough;
            if (ptnNode.ImageIndex == iImgNVSink)
                return SelectedHardwareType.NVSink;
            if (ptnNode.ImageIndex == iImgNVSource)
                return SelectedHardwareType.NVSource;
            if (ptnNode.ImageIndex == iImgSources)
            {
                if (ptnNode == SignalSources)
                    return SelectedHardwareType.Sources;
                else
                    return SelectedHardwareType.Views;
            }
            if (ptnNode.ImageIndex == iImgView)
                return SelectedHardwareType.View;

            if (ptnNode.ImageIndex == iImgSource)
                return SelectedHardwareType.Source;

            if (ptnNode.ImageIndex == iImgVerilog)
                return SelectedHardwareType.Verilog;

            if (ptnNode == Root)
                return SelectedHardwareType.Root;

            if (ptnNode.ImageIndex == iImgLog && ptnNode != Logs)
                return SelectedHardwareType.Log;

            return SelectedHardwareType.Unknown;
        }

        private void RecurseComponentTree(Component poComponent, TreeNode ptnParentNode)
        {
            TreeNode tnChild;
            
            TreeNode tnComponent = new TreeNode(poComponent.ToString(), iImgComponent, iImgComponent);
            tnComponent.Tag = poComponent;
            ptnParentNode.Nodes.Add(tnComponent);

            if (poComponent.ComponentVerilog.VerilogModuleName != null)
            {
                if (poComponent.ComponentVerilog.VerilogModuleName.Trim() != "")
                {
                    tnChild = new TreeNode(poComponent.ComponentVerilog.VerilogModuleName, iImgVerilog, iImgVerilog);
                    tnChild.Tag = poComponent.ComponentVerilog;
                    tnComponent.Nodes.Add(tnChild);
                }
            }
            
            TreeNode tnSignals = new TreeNode("Signals", iImgComponentSignals, iImgComponentSignals);
            tnComponent.Nodes.Add(tnSignals);
            TreeNode tnComponents = new TreeNode("Components", iImgComponentChildren, iImgComponentChildren);
            tnComponent.Nodes.Add(tnComponents);

            int iSignalCount = 0;    
            foreach (NodeVector oNodeVector in poComponent.SourceNodeVectors.Values)
            {
                tnChild = new TreeNode(oNodeVector.Name + " {" + oNodeVector.Size.ToString() + "}" , iImgNVSource, iImgNVSource);
                tnChild.Tag = oNodeVector;
                tnSignals.Nodes.Add(tnChild);
                iSignalCount++;
            }

            foreach (NodeVector oNodeVector in poComponent.SinkNodeVectors.Values)
            {
                tnChild = new TreeNode(oNodeVector.Name + " {" + oNodeVector.Size.ToString() + "}", iImgNVSink, iImgNVSink);
                tnChild.Tag = oNodeVector;
                tnSignals.Nodes.Add(tnChild);
                iSignalCount++;
            }

            foreach (NodeVector oNodeVector in poComponent.PassthroughNodeVectors.Values)
            {
                tnChild = new TreeNode(oNodeVector.Name + " {" + oNodeVector.Size.ToString() + "}", iImgNVPassthrough, iImgNVPassthrough);
                tnChild.Tag = oNodeVector;
                tnSignals.Nodes.Add(tnChild);
                iSignalCount++;
            }

            int iComponentCount=0;
            foreach (Component oChildComponent in poComponent.Components.Values)
            {
                RecurseComponentTree(oChildComponent, tnComponents);
                iComponentCount++;
            }

            if (iSignalCount > 0)
            {
                tnSignals.Text = tnSignals.Text + " {" + iSignalCount.ToString() + "}";
            }
            else
            {
                tnComponent.Nodes.Remove(tnSignals);
            }

            if (iComponentCount > 0)
            {
                tnComponents.Text = tnComponents.Text + " {" + iComponentCount.ToString() + "}";
            }
            else
            {
                tnComponent.Nodes.Remove(tnComponents);
            }

        }

        public void ExpandSignalView()
        {
            SignalViews.ExpandAll();
        }

        public void UnregisterTreeView()
        {
            oRapidHardware.DisplayManager.UnregisterTreeView(this);
        }

    }
}
